package com.cxyd.modules.wcs.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.cxyd.common.constant.Constants;
import com.cxyd.common.constant.RcsConstants;
import com.cxyd.common.constant.WcsConstants;
import com.cxyd.common.service.impl.CrudServiceImpl;
import com.cxyd.common.utils.ConvertUtils;
import com.cxyd.common.utils.StringUtils;
import com.cxyd.modules.api.dto.RcsResultHK;
import com.cxyd.modules.log.service.SysLogWorkService;
import com.cxyd.modules.wcs.dao.AgvTrkHkDao;
import com.cxyd.modules.wcs.dto.*;
import com.cxyd.modules.wcs.entity.AgvTrkHkEntity;
import com.cxyd.modules.wcs.entity.RouteSetEntity;
import com.cxyd.modules.wcs.entity.TrkEntity;
import com.cxyd.modules.wcs.service.AgvTrkHkService;
import com.cxyd.modules.wcs.service.RouteSetService;
import com.cxyd.modules.wcs.service.TrkService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.Instant;
import java.util.*;

@Service
@Slf4j
public class AgvTrkHkServiceImpl extends CrudServiceImpl<AgvTrkHkDao, AgvTrkHkEntity, AgvTrkHkDTO> implements AgvTrkHkService {
    @Resource
    private TrkService trkService;
    @Resource
    private RouteSetService routeSetService;
    @Resource
    private SysLogWorkService logWorkService;

    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public AgvTrkHkServiceImpl() {
    }

    @Override
    public QueryWrapper<AgvTrkHkEntity> getWrapper(Map<String, Object> params) {
        String trkId = (String) params.get("trkId");
        String ctnrCode = (String) params.get("ctnrCode");
        String taskCode = (String) params.get("taskCode");
        QueryWrapper<AgvTrkHkEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(StringUtils.isNotBlank(trkId), "trk_id", trkId);
        wrapper.eq(StringUtils.isNotBlank(ctnrCode), "ctnr_code", ctnrCode);
        wrapper.eq(StringUtils.isNotBlank(taskCode), "task_code", taskCode);
        return wrapper;
    }

    @Override
    public AgvTrkHkPostDTO getPostHkTrk() {
//      1.获取需下发的任务(入库任务需要一个一个下发,优先下料再上料)
        QueryWrapper<AgvTrkHkEntity> qw = new QueryWrapper<>();
        qw.lambda().eq(AgvTrkHkEntity::getStatus, 0)
                .orderBy(true, true, AgvTrkHkEntity::getCreateDate)
                .last("limit 1");
        AgvTrkHkEntity agvTrkHK = baseDao.selectOne(qw);
        if (agvTrkHK == null) {
            return null;
        }
        AgvTrkHkPostDTO postInfo = ConvertUtils.sourceToTarget(agvTrkHK, AgvTrkHkPostDTO.class);
//      规划搬送路径(不再通过配置,直接从起始与结束位置获取)
        List<String> paths = Arrays.asList(agvTrkHK.getPositionCode().split("#"));
        List<PositionPathDTO> positionCodePath = new ArrayList<>();
        paths.forEach(item -> {
            PositionPathDTO path = new PositionPathDTO();
            path.setType("00");
            path.setPositionCode(item);
            positionCodePath.add(path);
        });
        postInfo.setPositionCodePath(positionCodePath);
        return postInfo;
    }

    @Override
    public ApplyPassDTO getContinueHkTrk() {
        //1.获取请求输送线状态的任务
        QueryWrapper<AgvTrkHkEntity> qw = new QueryWrapper<>();
        qw.lambda().eq(AgvTrkHkEntity::getStatus, RcsConstants.HK_STATUS_CONTINUE)
                .orderBy(true, true, AgvTrkHkEntity::getUpdateDate)
                .last("limit 1");
        AgvTrkHkEntity agvTrkHK = baseDao.selectOne(qw);
        if (agvTrkHK == null) {
            return null;
        }
        //3.生成任务继续信号
        ApplyPassDTO passDTO = new ApplyPassDTO();
        passDTO.setReqCode(String.valueOf(System.currentTimeMillis()));
        passDTO.setTaskCode(agvTrkHK.getTaskCode());
        passDTO.setReqTime(dateFormat.format(new Date()));
        return passDTO;
    }

    @Override
    public void hkTrkScan(TrkEntity wcsTrk) {
//        0.解析任务
        if (wcsTrk == null) {
            return;
        }
        String workName = "[流程-SCAN]任务扫描-HK";
        String workProc = "AgvTrkHkServiceImpl.hkTrkScan";
        String pCode = WcsConstants.PROC_CODE_SUCCESS;
        String pMsg;
//        1.通过trkId尝试获取搬送任务是否存在
        AgvTrkHkEntity agvTrkHkEntity = getAgvTrkByContNo(wcsTrk.getContNo());
        if (agvTrkHkEntity != null) {
            //记录日志并返回
            pCode = "hkTrkScan_001";
            pMsg = "任务扫描异常!托盘[" + wcsTrk.getContNo() + "]任务已存在!";
            wcsTrk.setTrkSt(WcsConstants.TRK_STATUS_ERROR);
            wcsTrk.setComments(pMsg);
            wcsTrk.setUpdateDate(new Date());
            trkService.updateById(wcsTrk);
            logWorkService.workLogging(workName, wcsTrk.getContNo(), pCode, pMsg, "", workProc, WcsConstants.WCS_USER_NAME, 10L);
            return;
        }
        Long trkId = wcsTrk.getTrkId();
//        搬送路径与模板匹配
//        RouteSetEntity routeSetByPath = routeSetService.getRouteSetByType(wcsTrk.getTrkType());
        RouteSetEntity routeSetByPath = routeSetService.getRouteSetByPath(wcsTrk.getTrkType(), wcsTrk.getFrmPos(), wcsTrk.getToPos());
        String contNo = wcsTrk.getContNo();
        String contType = wcsTrk.getContType();
//        起始站点与目标站点均为实际站点,无需转换
        StringBuilder positionCode = new StringBuilder();
        if (WcsConstants.TRK_TYPE_IN.equals(wcsTrk.getTrkType()) && RcsConstants.HK_TASK_TYP_L401.equals(routeSetByPath.getTaskTyp())) {
            positionCode.append(wcsTrk.getFrmPos() + "_X#");
            positionCode.append(wcsTrk.getFrmPos() + "_D#");
            positionCode.append(wcsTrk.getFrmPos() + "#");
            positionCode.append(wcsTrk.getToPos());
        } else if (WcsConstants.TRK_TYPE_OT.equals(wcsTrk.getTrkType()) && RcsConstants.HK_TASK_TYP_L402.equals(routeSetByPath.getTaskTyp())) {
            positionCode.append(wcsTrk.getFrmPos() + "#");
            positionCode.append(wcsTrk.getToPos() + "_X#");
            positionCode.append(wcsTrk.getToPos() + "_D#");
            positionCode.append(wcsTrk.getToPos());
        } else {
//            非机台安全交互只需要将两个站点拼接即可
            positionCode.append(wcsTrk.getFrmPos() + "#");
            positionCode.append(wcsTrk.getToPos());
        }
//        数据写入[AGV_TRK_HK]表(taskCode使用有含义的编码规则:托盘条码+年月日+6位trkId)
        String taskCode = String.valueOf(System.currentTimeMillis());
        String taskTyp = routeSetByPath.getTaskTyp();
//        防止reqCode重复，使用料箱码+时间戳
        String reqCode = contNo + "#" + trkId;
//        任务优先级
        int trkPrty = wcsTrk.getTrkPrty();
        String taskMode = "0";
//        2.写入agv_trk_yf数据
        AgvTrkHkEntity agvTrkHkNew = new AgvTrkHkEntity();
        agvTrkHkNew.setTrkId(trkId);
//        wbCode用于记录工作台位置
        agvTrkHkNew.setPriority(WcsConstants.TRK_PRTY_DEF);
        agvTrkHkNew.setReqCode(reqCode);
        agvTrkHkNew.setTaskCode(taskCode);
        agvTrkHkNew.setTaskTyp(taskTyp);
        agvTrkHkNew.setPositionCode(positionCode.toString());
//        CTU装载的容器编号
        agvTrkHkNew.setCtnrCode(contNo);
        agvTrkHkNew.setAgvTyp(contType);
        agvTrkHkNew.setPodCode(contNo);
        agvTrkHkNew.setPodType(contType);
//        将任务类型写入AGV_TYP中
        agvTrkHkNew.setTaskMode(taskMode);
        agvTrkHkNew.setPriority(String.valueOf(trkPrty));
        agvTrkHkNew.setCreator(WcsConstants.WCS_USER_ID);
        baseDao.insert(agvTrkHkNew);
//        3.更新wcs_trk数据
        pMsg = "容器[" + contNo + "]生成[HK-AGV]搬送任务！关联ID[" + agvTrkHkNew.getId() + "]";
        wcsTrk.setTrkSt(WcsConstants.TRK_STATUS_RUNNING);
        wcsTrk.setComments(pMsg);
        wcsTrk.setUpdateDate(new Date());
        trkService.updateById(wcsTrk);
        logWorkService.workLogging(workName, wcsTrk.getContNo(), pCode, pMsg, "", workProc, WcsConstants.WCS_USER_NAME, 0);
    }

    @Override
    public int getAgvTrkCount() {
        return baseDao.getAgvTrkSumByState();
    }

    @Override
    public AgvTrkHkEntity getAgvTrkByTrkId(long id) {
        QueryWrapper<AgvTrkHkEntity> qw = new QueryWrapper<>();
        qw.lambda().eq(AgvTrkHkEntity::getTrkId, id)
                .last("limit 1");
        return baseDao.selectOne(qw);
    }

    @Override
    public AgvTrkHkEntity getAgvTrkByContNo(String contNo) {
        if (StringUtils.isEmpty(contNo)) {
            return null;
        }
        QueryWrapper<AgvTrkHkEntity> qw = new QueryWrapper<>();
        qw.lambda().eq(AgvTrkHkEntity::getCtnrCode, contNo)
                .last("limit 1");
        return baseDao.selectOne(qw);
    }

    @Override
    public AgvTrkHkEntity getAgvTrkByTaskCode(String taskCode) {
        if (StringUtils.isEmpty(taskCode)) {
            return null;
        }
        QueryWrapper<AgvTrkHkEntity> qw = new QueryWrapper<>();
        qw.lambda().eq(AgvTrkHkEntity::getTaskCode, taskCode)
                .ne(AgvTrkHkEntity::getStatus, RcsConstants.AGV_TRK_HK_CANCEL)
                .last("limit 1");
        return baseDao.selectOne(qw);
    }

    @Override
    public void agvTrkHandle(AgvTrkHkPostDTO dto, RcsResultHK response) {
//        1.判断任务是否下发成功
        String msg = response.getMessage();
//        3.定义状态
        String pCode = WcsConstants.PROC_CODE_SUCCESS;
        String pMsg = "搬送任务成功下发[HK-AGV]!任务编号[" + dto.getTaskCode() + "]";
        int status;
        if (Constants.SUCCESS.equals(response.getCode())) {
            status = RcsConstants.HK_STATUS_POST;
//            成功下发更新[wcs_trk]任务状态
        } else {
            status = RcsConstants.HK_STATUS_ERROR;
            pCode = "agvTrkHandle_001";
            pMsg = "搬送任务下发失败!rcs反馈异常:" + msg;
        }
//        开始时间-start
        Instant start = Instant.now();
//        4.条件更新语句
        UpdateWrapper<AgvTrkHkEntity> uw = new UpdateWrapper<>();
        uw.lambda().set(AgvTrkHkEntity::getStatus, status)
                .set(AgvTrkHkEntity::getData, msg)
                .set(AgvTrkHkEntity::getReqTime, dateFormat.format(new Date()))
                .set(AgvTrkHkEntity::getUpdater, WcsConstants.WCS_USER_ID)
                .set(AgvTrkHkEntity::getUpdateDate, new Date())
                .eq(AgvTrkHkEntity::getReqCode, dto.getReqCode());
        baseDao.update(null, uw);
//        结束时间-end
        Instant end = Instant.now();
//        5.日志记录
        String workName = "[流程-POST]任务下发-HK";
        String workProc = "AgvTrkHkServiceImpl.agvTrkHandle";
//        计算耗时
        Duration times = Duration.between(start, end);
        logWorkService.workLogging(workName, dto.getTaskCode(), pCode, pMsg, "", workProc, WcsConstants.WCS_USER_NAME, times.toMillis());
    }

    @Override
    public void agvPassHandle(ApplyPassDTO dto, RcsResultHK response) {
//        1.判断任务是否下发成功
//        2.成功下发更新任务状态为执行中,失败则记录失败原因
        if (StringUtils.isEmpty(response.getReqCode())) {
            return;
        }
        String msg = response.getMessage();
//        通过ReqCode获取取放申请的任务
        QueryWrapper<AgvTrkHkEntity> qw = new QueryWrapper<>();
        qw.lambda().eq(AgvTrkHkEntity::getTaskCode, dto.getTaskCode()).last("limit 1");
        AgvTrkHkEntity agvTrk = baseDao.selectOne(qw);
        String pCode = "0";
        String pMsg = "任务单[" + agvTrk.getTaskCode() + "]对应状态[" + agvTrk.getStatus() + "]的任务继续信号下发成功!";
        int status = RcsConstants.HK_STATUS_CONTINUE;
        if (Constants.SUCCESS.equals(response.getCode())) {
            status = RcsConstants.HK_STATUS_TAKE;
//            成功下发更新[wcs_trk]任务状态
        } else {
//            下发异常后继续下发
//            status = RcsConstants.HK_STATUS_ERROR;
            pCode = "agvPassHandle_error_001";
            pMsg = "任务单[" + agvTrk.getTaskCode() + "]对应状态[" + agvTrk.getStatus() + "]的任务继续下发异常!rcs反馈:" + msg;
        }
//        更新agv_trk状态
        agvTrk.setStatus(status);
        agvTrk.setData(pMsg);
        agvTrk.setUpdateDate(new Date());
        baseDao.updateById(agvTrk);
        String workName = "[流程-CONTINUE]-任务继续-HK";
        String workProc = "AgvTrkService.agvPassHandle";
        logWorkService.workLogging(workName, agvTrk.getCtnrCode(), pCode, pMsg, "", workProc, WcsConstants.WCS_USER_NAME, 0);
    }

    @Override
    public void updateAgvTrkByContNo(String contNo) {
        QueryWrapper<AgvTrkHkEntity> qw = new QueryWrapper<>();
        qw.lambda().eq(AgvTrkHkEntity::getPodCode, contNo)
                .last("limit 1");
        AgvTrkHkEntity AgvTrkHkEntity = baseDao.selectOne(qw);
        if (AgvTrkHkEntity == null) {
            return;
        }
//        1.转移历史表
        baseDao.backupAgvTrk(contNo);
        baseDao.deleteById(AgvTrkHkEntity);
    }

    @Override
    public void updateAgvTrkByTaskCode(String taskCode) {
//        1.转移历史表
        baseDao.backupAgvTrkByTaskCode(taskCode);
//        2.删除表数据
        baseDao.deleteAgvTrkByTaskCode(taskCode);
    }

    @Override
    public AgvCancelHkDTO getCancelHkTrk() {
        //1.获取请求输送线状态的任务
        QueryWrapper<AgvTrkHkEntity> qw = new QueryWrapper<>();
        qw.lambda().eq(AgvTrkHkEntity::getStatus, RcsConstants.AGV_TRK_HK_CANCEL)
                .last("limit 1");
        AgvTrkHkEntity agvTrkHK = baseDao.selectOne(qw);
        if (agvTrkHK == null) {
            return null;
        }
        AgvCancelHkDTO dto = new AgvCancelHkDTO();
        dto.setReqCode(UUID.randomUUID().toString().replaceAll("-", ""));
        dto.setReqTime(dateFormat.format(new Date()));
        dto.setTaskCode(agvTrkHK.getTaskCode());
        dto.setForceCancel("0");
//        dto.setAgvCode(agvTrkHK.getAgvCode());
        return dto;
    }

    @Override
    public void agvCancelHandle(AgvCancelHkDTO dto, RcsResultHK respond) {
        if (StringUtils.isEmpty(respond.getReqCode())) {
            return;
        }
        //1.获取任务单
        String taskCode = dto.getTaskCode();
        AgvTrkHkEntity agvTrkHK = baseDao.selectOne(new QueryWrapper<AgvTrkHkEntity>().lambda().eq(AgvTrkHkEntity::getTaskCode, taskCode));
        if (agvTrkHK == null) {
            return;
        }
        //2.更新任务单状态
        agvTrkHK.setStatus(RcsConstants.HK_STATUS_END);
        agvTrkHK.setData(respond.getMessage());
        agvTrkHK.setUpdateDate(new Date());
        baseDao.updateById(agvTrkHK);
        //3.记录日志
        String workName = "[流程-任务取消]-HK";
        String workProc = "AgvTrkHkServiceImpl.agvCancelHandle";
        String code = "0";
        String msg = "AGV任务[" + taskCode + "]取消成功!";
        logWorkService.workLogging(workName, taskCode, code, msg, "", workProc, WcsConstants.WCS_USER_NAME, 0);
    }
}
